/**
 * 通用工具函数库
 * 合并项目中重复使用的工具函数，提供统一的工具方法
 */

import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import type { App } from 'vue'

// ==================== 类型定义 ====================
export interface ApiResponse<T = unknown> {
  code: number
  message: string
  data: T
  success: boolean
}

export interface PaginationParams {
  page: number
  size: number
  total?: number
}

export interface SelectOption {
  label: string
  value: string | number | boolean
  disabled?: boolean
  children?: SelectOption[]
}

export interface TreeOption {
  id: string | number
  label: string
  children?: TreeOption[]
  disabled?: boolean
  [key: string]: unknown
}

// ==================== 消息提示工具 ====================
export const message = {
  success: (msg: string, duration = 3000) => {
    ElMessage.success({
      message: msg,
      duration,
      showClose: true
    })
  },

  error: (msg: string, duration = 3000) => {
    ElMessage.error({
      message: msg,
      duration,
      showClose: true
    })
  },

  warning: (msg: string, duration = 3000) => {
    ElMessage.warning({
      message: msg,
      duration,
      showClose: true
    })
  },

  info: (msg: string, duration = 3000) => {
    ElMessage.info({
      message: msg,
      duration,
      showClose: true
    })
  },

  loading: (msg: string) => {
    return ElMessage({
      message: msg,
      type: 'info',
      duration: 0,
      showClose: false
    })
  }
}

export const notification = {
  success: (title: string, message: string, duration = 4500) => {
    ElNotification.success({
      title,
      message,
      duration,
      position: 'top-right'
    })
  },

  error: (title: string, message: string, duration = 4500) => {
    ElNotification.error({
      title,
      message,
      duration,
      position: 'top-right'
    })
  },

  warning: (title: string, message: string, duration = 4500) => {
    ElNotification.warning({
      title,
      message,
      duration,
      position: 'top-right'
    })
  },

  info: (title: string, message: string, duration = 4500) => {
    ElNotification.info({
      title,
      message,
      duration,
      position: 'top-right'
    })
  }
}

export const confirm = {
  delete: (title = '确认删除', content = '此操作将永久删除该数据，是否继续？') => {
    return ElMessageBox.confirm(content, title, {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
      confirmButtonClass: 'el-button--danger'
    })
  },

  custom: (title: string, content: string, options?: Record<string, unknown>) => {
    return ElMessageBox.confirm(content, title, {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
      ...options
    })
  },

  alert: (title: string, content: string, options?: Record<string, unknown>) => {
    return ElMessageBox.alert(content, title, {
      confirmButtonText: '确定',
      ...options
    })
  }
}

// 兼容 Element Plus 的 MessageBox 类型
export const messageBox = ElMessageBox

// ==================== 数据格式化工具 ====================
export const formatter = {
  // 日期格式化
  date: (date: string | Date, format = 'YYYY-MM-DD HH:mm:ss') => {
    if (!date) return ''
    const d = new Date(date)
    if (isNaN(d.getTime())) return ''
    
    const year = d.getFullYear()
    const month = String(d.getMonth() + 1).padStart(2, '0')
    const day = String(d.getDate()).padStart(2, '0')
    const hours = String(d.getHours()).padStart(2, '0')
    const minutes = String(d.getMinutes()).padStart(2, '0')
    const seconds = String(d.getSeconds()).padStart(2, '0')
    
    return format
      .replace('YYYY', String(year))
      .replace('MM', month)
      .replace('DD', day)
      .replace('HH', hours)
      .replace('mm', minutes)
      .replace('ss', seconds)
  },

  // 文件大小格式化
  fileSize: (size: number) => {
    if (size < 1024) return `${size} B`
    if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`
    if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`
    return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`
  },

  // 数字格式化
  number: (num: number, decimals = 2) => {
    if (isNaN(num)) return '0'
    return num.toLocaleString('zh-CN', {
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals
    })
  },

  // 货币格式化
  currency: (amount: number, currency = 'CNY') => {
    if (isNaN(amount)) return '¥0.00'
    return new Intl.NumberFormat('zh-CN', {
      style: 'currency',
      currency
    }).format(amount)
  },

  // 百分比格式化
  percent: (value: number, decimals = 2) => {
    if (isNaN(value)) return '0%'
    return `${(value * 100).toFixed(decimals)}%`
  },

  // 手机号格式化
  phone: (phone: string) => {
    if (!phone) return ''
    const cleaned = phone.replace(/\D/g, '')
    if (cleaned.length === 11) {
      return cleaned.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3')
    }
    return phone
  },

  // 身份证号格式化
  idCard: (idCard: string) => {
    if (!idCard) return ''
    const cleaned = idCard.replace(/\D/g, '')
    if (cleaned.length === 18) {
      return cleaned.replace(/(\d{6})(\d{8})(\d{4})/, '$1-$2-$3')
    }
    return idCard
  }
}

// ==================== 数据验证工具 ====================
export const validator = {
  // 邮箱验证
  email: (email: string) => {
    const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    return re.test(email)
  },

  // 手机号验证
  phone: (phone: string) => {
    const re = /^1[3-9]\d{9}$/
    return re.test(phone)
  },

  // 身份证号验证
  idCard: (idCard: string) => {
    const re = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
    return re.test(idCard)
  },

  // URL验证
  url: (url: string) => {
    try {
      new URL(url)
      return true
    } catch {
      return false
    }
  },

  // 密码强度验证
  password: (password: string) => {
    const minLength = 6
    const maxLength = 20
    const hasLetter = /[a-zA-Z]/.test(password)
    const hasNumber = /\d/.test(password)
    const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(password)
    
    return {
      valid: password.length >= minLength && password.length <= maxLength,
      strength: (hasLetter ? 1 : 0) + (hasNumber ? 1 : 0) + (hasSpecial ? 1 : 0),
      message: password.length < minLength ? '密码长度不能少于6位' :
               password.length > maxLength ? '密码长度不能超过20位' : ''
    }
  }
}

// ==================== 数据处理工具 ====================
export const dataUtils = {
  // 深拷贝
  deepClone: <T>(obj: T): T => {
    if (obj === null || typeof obj !== 'object') return obj
    if (obj instanceof Date) return new Date(obj.getTime()) as T
    if (obj instanceof Array) return obj.map(item => dataUtils.deepClone(item)) as T
    if (typeof obj === 'object') {
      const clonedObj = {} as Record<string, unknown>
      for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          clonedObj[key] = dataUtils.deepClone(obj[key])
        }
      }
      return clonedObj as T
    }
    return obj
  },

  // 数组去重
  unique: <T>(arr: T[], key?: keyof T): T[] => {
    if (!key) return [...new Set(arr)]
    const seen = new Set()
    return arr.filter(item => {
      const value = item[key]
      if (seen.has(value)) return false
      seen.add(value)
      return true
    })
  },

  // 数组分组
  groupBy: <T>(arr: T[], key: keyof T): Record<string, T[]> => {
    return arr.reduce((groups, item) => {
      const value = String(item[key])
      if (!groups[value]) groups[value] = []
      groups[value].push(item)
      return groups
    }, {} as Record<string, T[]>)
  },

  // 数组排序
  sortBy: <T>(arr: T[], key: keyof T, order: 'asc' | 'desc' = 'asc'): T[] => {
    return [...arr].sort((a, b) => {
      const aVal = a[key]
      const bVal = b[key]
      if (aVal < bVal) return order === 'asc' ? -1 : 1
      if (aVal > bVal) return order === 'asc' ? 1 : -1
      return 0
    })
  },

  // 树形数据转换
  arrayToTree: <T extends { id: string | number; parentId?: string | number }>(
    arr: T[],
    parentId: string | number | null = null
  ): TreeOption[] => {
    return arr
      .filter(item => item.parentId === parentId)
      .map(item => ({
        label: String((item as Record<string, unknown>).name || (item as Record<string, unknown>).title || item.id),
        children: dataUtils.arrayToTree(arr, item.id),
        ...item
      }))
  },

  // 树形数据扁平化
  treeToArray: <T extends { children?: T[] }>(tree: T[]): T[] => {
    const result: T[] = []
    const traverse = (nodes: T[]) => {
      nodes.forEach(node => {
        result.push(node)
        if (node.children) {
          traverse(node.children)
        }
      })
    }
    traverse(tree)
    return result
  },

  // 查找树节点
  findTreeNode: <T extends { id: string | number; children?: T[] }>(
    tree: T[],
    id: string | number
  ): T | null => {
    for (const node of tree) {
      if (node.id === id) return node
      if (node.children) {
        const found = dataUtils.findTreeNode(node.children, id)
        if (found) return found
      }
    }
    return null
  }
}

// ==================== 字符串工具 ====================
export const stringUtils = {
  // 首字母大写
  capitalize: (str: string) => {
    return str.charAt(0).toUpperCase() + str.slice(1)
  },

  // 驼峰转换
  camelCase: (str: string) => {
    return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
  },

  // 短横线转换
  kebabCase: (str: string) => {
    return str.replace(/([A-Z])/g, '-$1').toLowerCase()
  },

  // 下划线转换
  snakeCase: (str: string) => {
    return str.replace(/([A-Z])/g, '_$1').toLowerCase()
  },

  // 截取字符串
  truncate: (str: string, length: number, suffix = '...') => {
    if (str.length <= length) return str
    return str.slice(0, length) + suffix
  },

  // 生成随机字符串
  random: (length = 8) => {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    let result = ''
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length))
    }
    return result
  }
}

// ==================== 存储工具 ====================
export const storage = {
  // 本地存储
  local: {
    get: <T>(key: string, defaultValue?: T): T | null => {
      try {
        const item = localStorage.getItem(key)
        return item ? JSON.parse(item) : defaultValue || null
      } catch {
        return defaultValue || null
      }
    },

    set: <T>(key: string, value: T): void => {
      try {
        localStorage.setItem(key, JSON.stringify(value))
      } catch (error) {
        console.error('LocalStorage set error:', error)
      }
    },

    remove: (key: string): void => {
      localStorage.removeItem(key)
    },

    clear: (): void => {
      localStorage.clear()
    }
  },

  // 会话存储
  session: {
    get: <T>(key: string, defaultValue?: T): T | null => {
      try {
        const item = sessionStorage.getItem(key)
        return item ? JSON.parse(item) : defaultValue || null
      } catch {
        return defaultValue || null
      }
    },

    set: <T>(key: string, value: T): void => {
      try {
        sessionStorage.setItem(key, JSON.stringify(value))
      } catch (error) {
        console.error('SessionStorage set error:', error)
      }
    },

    remove: (key: string): void => {
      sessionStorage.removeItem(key)
    },

    clear: (): void => {
      sessionStorage.clear()
    }
  }
}

// ==================== 异步工具 ====================
export const asyncUtils = {
  // 延迟执行
  sleep: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)),

  // 重试机制
  retry: async <T>(
    fn: () => Promise<T>,
    maxAttempts = 3,
    delay = 1000
  ): Promise<T> => {
    let lastError: Error | undefined
    for (let i = 0; i < maxAttempts; i++) {
      try {
        return await fn()
      } catch (error) {
        lastError = error as Error
        if (i < maxAttempts - 1) {
          await asyncUtils.sleep(delay * Math.pow(2, i))
        }
      }
    }
    throw lastError || new Error('Retry failed')
  },

  // 超时控制
  timeout: <T>(promise: Promise<T>, ms: number): Promise<T> => {
    return Promise.race([
      promise,
      new Promise<never>((_, reject) =>
        setTimeout(() => reject(new Error('Operation timeout')), ms)
      )
    ])
  },

  // 并发控制
  concurrency: async <T>(
    tasks: (() => Promise<T>)[],
    limit = 5
  ): Promise<T[]> => {
    const results: T[] = []
    const executing: Promise<void>[] = []

    for (const task of tasks) {
      const promise = task().then(result => {
        results.push(result)
      })
      executing.push(promise)

      if (executing.length >= limit) {
        await Promise.race(executing)
        executing.splice(executing.findIndex(p => p === promise), 1)
      }
    }

    await Promise.all(executing)
    return results
  }
}

// ==================== 设备检测工具 ====================
export const device = {
  // 是否为移动设备
  isMobile: () => {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
      navigator.userAgent
    )
  },

  // 是否为平板设备
  isTablet: () => {
    return /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768
  },

  // 是否为桌面设备
  isDesktop: () => {
    return !device.isMobile() && !device.isTablet()
  },

  // 获取设备类型
  getType: () => {
    if (device.isMobile()) return 'mobile'
    if (device.isTablet()) return 'tablet'
    return 'desktop'
  }
}

// ==================== 全局属性设置 ====================
export const setupGlobalUtils = (app: App) => {
  // 设置全局属性
  app.config.globalProperties.$messageUtils = message
  app.config.globalProperties.$notification = notification
  app.config.globalProperties.$messageBox = messageBox
  app.config.globalProperties.$formatter = formatter
  app.config.globalProperties.$validator = validator
  app.config.globalProperties.$dataUtils = dataUtils
  app.config.globalProperties.$stringUtils = stringUtils
  app.config.globalProperties.$storage = storage
  app.config.globalProperties.$asyncUtils = asyncUtils
  app.config.globalProperties.$device = device

  // 设置全局方法
  app.config.globalProperties.$sleep = asyncUtils.sleep
  app.config.globalProperties.$formatDate = formatter.date
  app.config.globalProperties.$formatFileSize = formatter.fileSize
}

// ==================== 导出所有工具 ====================
export default {
  message,
  notification,
  confirm,
  formatter,
  validator,
  dataUtils,
  stringUtils,
  storage,
  asyncUtils,
  device,
  setupGlobalUtils
}
